#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
int main()
{
  pid_t id = fork();
  if (!id)
  {
    //子进程//返回0
    int n = 5;
    while (n--)
    {
      printf("我是子进程！ 我的pid：%d，我的ppid：%d \n", getpid(), getppid());
      sleep(1);
      // int*p=NULL;
      // *p=100;//野指针 出现段错误 信号11
      // int err= 10/0;// 除0 出现浮点指针错误 信号8

      // 也可以自行 kill -信号 杀掉进程
    }
    exit(104); //退出码
  }
  else if (id > 0)
  // {
  // //若主动对CHLD信号设置忽略,子进程退出会自动释放资源,并且不给父进程发送信号,父进程也无法获取子进程退出信息
  // //若阻塞等待,会在子进程还在运行时阻塞住,子进程退出后返回errno(No child processes)
  // //WNOHANG会在子进程还在跑的时候返回0 但和 阻塞等待一样 子进程退出后返回errno:No child processes(说明子进程自动释放资源)
  // signal(SIGCHLD, SIG_IGN);
  //   //父进程//返回子进程的pid
  //   printf("我是父进程！ 我的pid：%d，我的ppid：%d \n", getpid(), getppid());
  //   int sta = 0;
  //    //非阻塞等待
  //    //轮转问询
  //     pid_t ret=0;
  //     while(1 ){//错误写法 ret=waitpid(id,&sta,WNOHANG) 返回0无法进入循环
  //       ret=waitpid(id,&sta,WNOHANG);//正确写法 轮转问询
  //       if(ret>0){//等待成功
  //         if(WIFEXITED(sta)){//这个宏可以检查是否正常退出
  //              printf("等待成功，正常退出！ exit code: %d \n",WEXITSTATUS(sta)); //这个宏可以获取退出码
  //         }
  //         else{
  //              printf("等待成功，异常退出！exit sig: %d core_dump: %d \n",sta&0x7F,sta>>7&0x1);//信号要自己拿
  //            }
  //         break;
  //      }
  //      else if(ret==0){//还有子进程没退出
  //        printf("子进程还没退出 我父进程就去干其他事情拉！\n");
  //      }
  //         else{//错误,如没有子进程了
  //            printf("%s\n:", strerror(errno));
  //            return errno;
  //         }
  //       sleep(1);
  //     }
  //     }
  //阻塞等待
  {
    signal(SIGCHLD, SIG_IGN);
    int sta = 0;
    pid_t ret = waitpid(id, &sta, 0); //第一个参数是要等待的子进程pid 如果是-1 就代表等待任意一个子进程
                                      //第二个为输出型参数 退出码或信号
                                      //第三个为等待模式 0 为阻塞等待 WNOHANG 为非阻塞等待
    printf(".....\n");//虽然设置了忽略但在子进程退出前也是阻塞住的
    if (ret > 0)
    {
      // printf("等待成功： pid:%d  exit sig: %d exit code:%d core_dump：%d \n",ret,sta&0x7F,sta>>8&0xFF,sta>>7&&0x1);//低七位和高八位表示信号 ， 退出码
      //第八位为coredump标记为，如果环境允许且信号为core型的，会将进程上下文保存再core文件内，如果成功生成了文件，则为1否则为0.
      // 一般线上云服务器环境都默认关闭的，因为产品都上线了，一般不会再线上调试 ，而是 一般服务崩了都会立马自动重启，可能会不停产生core文件，甚至把磁盘写满。
      //如果正常退出那高八位就是0 没有0号信号
      //位运算有学习成本 因此系统提供了宏
      if (WIFEXITED(sta))                                                  //这个宏可以检查是否正常退出
        printf("等待成功，正常退出！ exit code: %d \n", WEXITSTATUS(sta)); //这个宏可以获取退出码
      else
        printf("等待成功，异常退出！exit sig: %d core_dump: %d \n", sta & 0x7F, sta >> 7 & 0x1); //也可以自己拿
    }
    else
    {
      printf("%s\n:", strerror(errno));
      return errno;
    }
  }
  return 0;
}
